﻿// <copyright>
// Copyright (c) 2008 - 2009, Microsoft, All Rights Reserved
// </copyright>
//
// Licensed under the Microsoft Public License (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
//
// http://www.opensource.org/licenses/ms-pl.html

namespace LiveLabs.Logging.Logs
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using LiveLabs.Logging.Resources;
    using LiveLabs.Logging.Util;

    /// <summary>
    /// Implementation of <see cref="Log"/> that writes to any <see cref="System.IO.TextWriter"/>.
    /// </summary>
    /// <remarks>
    /// <para>
    /// Since the TextWriter can be fronting any source (File, Socket, etc.), all exceptions
    /// are caught and traced out as warnings.
    /// </para>
    /// <para>
    /// This implementation is NOT thread safe.  Only 1 thread at a time may write.  See 
    /// <see cref="LockingLog"/> as a way to make a TextWriterLog thread safe.
    /// </para>
    /// </remarks>
    public class TextWriterLog : Log, IDisposable
    {
        private readonly TextWriterResponsibility responsibility;

        private volatile bool disposed;

        private TextWriter writer;

        /// <summary>
        /// Initializes a new instance of the TextWriterLog class.
        /// </summary>
        /// <param name="writer">The <see cref="System.IO.TextWriter"/> to write to.</param>
        /// <remarks>
        /// This constructor implies the <paramref name="writer"/> is not owned by the instance.
        /// </remarks>
        public TextWriterLog(TextWriter writer)
            : this(writer, TextWriterResponsibility.DoesNotOwn)
        {
        }

        /// <summary>
        /// Initializes a new instance of the TextWriterLog class.
        /// </summary>
        /// <param name="writer">The <see cref="System.IO.TextWriter"/> to write to.</param>
        /// <param name="responsibility">The responbility level this instance has over the <paramref name="writer"/></param>
        public TextWriterLog(TextWriter writer, TextWriterResponsibility responsibility)
        {
            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            this.responsibility = responsibility;
            this.disposed = false;
            this.writer = writer;
        }

        /// <summary>
        /// Writes the message to the underlying <see cref="System.IO.TextWriter"/> 
        /// </summary>
        /// <param name="message">The message to write</param>
        /// <param name="level">The level of the message.  Ignored.</param>
        public override void WriteLine(string message, LogLevel level)
        {
            if (this.disposed)
            {
                throw new ObjectDisposedException(GetType().FullName);
            }

            try
            {
                this.writer.WriteLine(message);
                this.writer.Flush();
            }
            catch (Exception ex)
            {
                if (ex.IsImportant())
                {
                    throw;
                }

#if SILVERLIGHT
                Debug.WriteLine(Messages.WriterWriteFailed, ex);
#else
                Trace.TraceWarning(Messages.WriterWriteFailed, ex);
#endif
            }
        }

        /// <summary>
        /// Disposes of resources this instance holds onto.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Called to dispose of any resources this instance holds.
        /// </summary>
        /// <param name="disposing">True if being called from Dispose, false otherwise.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (this.disposed)
            {
                return;
            }

            try
            {
                if (disposing)
                {
                    if (this.writer != null)
                    {
                        if (this.responsibility == TextWriterResponsibility.Owns)
                        {
                            this.writer.Dispose();
                        }

                        this.writer = null;
                    }
                }
            }
            finally
            {
                // no matter what we are disposed
                this.disposed = true;
            }
        }
    }
}
